<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>class 的用法和作用</title>
  </head>
  <body>
    <script>
      // class Person {
      //   constructor() {
      //     this.name = "person";
      //   }

      //   say() {
      //     console.log("hello");
      //   }
      // }

      // const Animal = function() {};
      // Animal.prototype.toString = function() {};

      // // 类的内部所有定义的方法，都是不可枚举的（non-enumerable）和 ES5不同。
      // console.log(Object.keys(Animal.prototype)); // ["toString"]
      // console.log(Object.keys(Person.prototype)); // []

      // 取值函数（getter）和存值函数（setter）
      // class MyClass {
      //   constructor() {}
      //   get prop() {
      //     return "getter";
      //   }
      //   set prop(value) {
      //     console.log("setter: " + value);
      //   }
      // }

      // let inst = new MyClass();
      // console.log(inst.prop);
      // inst.prop = "...";

      // 类不存在变量提升（hoist），这一点与 ES5 完全不同。
      // new Foo(); // ReferenceError
      // class Foo {}

      // 静态方法和属性
      // 静态方法
      // 类相当于实例的原型，所有在类中定义的方法，都会被实例继承。如果在一个方法前，加上static关键字，就表示该方法不会被实例继承，而是直接通过类来调用，这就称为“静态方法”。
      // class Foo {
      //   static classMethod() {
      //     return "hello";
      //   }
      // }
      // Foo.classMethod(); // 'hello'
      // var foo = new Foo();
      // foo.classMethod(); //  Uncaught TypeError: foo.classMethod is not a function

      // 注意，如果静态方法包含this关键字，这个this指的是类，而不是实例。
      // class Foo {
      //   static bar() {
      //     this.baz();
      //   }
      //   static baz() {
      //     console.log("hello");
      //   }
      //   baz() {
      //     console.log("world");
      //   }
      // }
      // Foo.bar(); // hello

      // // 父类的静态方法，可以被子类继承。
      // class Bar extends Foo {}
      // Bar.baz(); // 'hello'

      // // 静态方法也是可以从super对象上调用的。
      // class Bar extends Foo {
      //   static baz() {
      //     return super.baz() + ", too";
      //   }
      // }
      // Bar.baz();

      // 静态属性
      // 静态属性指的是 Class 本身的属性，即Class.propName，而不是定义在实例对象（this）上的属性。
      // class Foo {}
      // Foo.prop = 1;
      // Foo.prop; // 1

      // // 新写法
      // class Fbb {
      //   static prop = 1;
      // }

      // 私有方法和属性
      // 私有方法和私有属性，是只能在类的内部访问的方法和属性，外部不能访问。这是常见需求，有利于代码的封装，但 ES6 不提供，只能通过变通方法模拟实现。
      // const bar = Symbol("bar");
      // const snaf = Symbol("snaf");

      // class myClass {
      //   // 公有方法
      //   foo(baz) {
      //     return this[bar](baz);
      //   }

      //   // 私有方法
      //   [bar](baz) {
      //     this[snaf] = baz;
      //     return this[snaf];
      //   }
      // }
      // console.log(new myClass().foo("jjjjj")); //  jjjjj
      // // 上面 bar和snaf都是Symbol值，一般情况下无法获取到它们，因此达到了私有方法和私有属性的效果。但是也不是绝对不行，Reflect.ownKeys()依然可以拿到它们。
      // console.log(Reflect.ownKeys(myClass.prototype)); // ["constructor", "foo", Symbol(bar)]

      // 私有属性的提案
      class IncreasingCounter {
        #count = 0;
        get value() {
          console.log("Getting the current value!");
          return this.#count;
        }
        increment() {
          this.#count++;
        }
      }

      // const counter = new IncreasingCounter();
      // counter.#count // 报错  Uncaught SyntaxError: Private field '#count' must be declared in an enclosing class
      // counter.#count = 42 // 报错  Uncaught SyntaxError: Private field '#count' must be declared in an enclosing class

      // 私有属性不限于从this引用，只要是在类的内部，实例也可以引用私有属性。
      class Foo {
        #privateValue = 42;
        static getPrivateValue(foo) {
          return foo.#privateValue;
        }
      }
      console.log(Foo.getPrivateValue(new Foo())); // 42



      
    </script>
  </body>
</html>
